package com.xxmw.transaction.service.robot.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxmw.transaction.common.entity.P;
import com.xxmw.transaction.common.excep.service.TransactionException;
import com.xxmw.transaction.common.utils.Constant;
import com.xxmw.transaction.common.utils.bourse.BinanceUtil;
import com.xxmw.transaction.common.utils.bourse.BitforexUtil;
import com.xxmw.transaction.common.utils.bourse.HuobiUtil;
import com.xxmw.transaction.common.utils.bourse.OkexUtil;
import com.xxmw.transaction.enumeration.TradeTypeEnum;
import com.xxmw.transaction.mapper.robot.RobotOrderMapper;
import com.xxmw.transaction.model.app.BourseApi;
import com.xxmw.transaction.model.app.BourseOrder;
import com.xxmw.transaction.model.app.BoursePrice;
import com.xxmw.transaction.model.app.Symbol;
import com.xxmw.transaction.model.robot.RobotOrder;
import com.xxmw.transaction.model.robot.RobotStrategy;
import com.xxmw.transaction.service.SysDictService;
import com.xxmw.transaction.service.app.BourseApiService;
import com.xxmw.transaction.service.app.SymbolService;
import com.xxmw.transaction.service.app.SymbolSubService;
import com.xxmw.transaction.service.robot.RobotOrderService;
import com.xxmw.transaction.service.robot.RobotStrategyService;
import com.xxmw.transaction.vo.ClassifyVolumeVo;
import com.xxmw.transaction.vo.RobotOrderVo;
import com.xxmw.transaction.vo.SymbolVolumeVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @author luowenliang
 * @since 2020/2/17 15:52
 */
@Slf4j
@Service
public class RobotOrderServiceImpl extends ServiceImpl<RobotOrderMapper, RobotOrder> implements RobotOrderService, InitializingBean {

    private static final ExecutorService executorService = Executors.newCachedThreadPool();

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Autowired
    private BourseApiService bourseApiService;

    @Autowired
    private SymbolSubService symbolSubService;

    @Autowired
    private SymbolService symbolService;

    @Autowired
    private RobotStrategyService robotStrategyService;

    @Autowired
    private SysDictService sysDictService;

    @Override
    public P<RobotOrder> pageList(Integer pageNum, Integer pageSize, Long id, String ourId, Integer bourse, Integer status,String symbol) {
        QueryWrapper<RobotOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("created");
        queryWrapper.eq(null != id, "id", id);
        queryWrapper.eq(null != bourse, "bourse", bourse);
        queryWrapper.eq(null != status, "status", status);
        queryWrapper.eq(StringUtils.isNotBlank(ourId), "our_id", ourId);
        queryWrapper.eq(StringUtils.isNotBlank(symbol), "symbol", symbol);
        IPage<RobotOrder> page = new Page<>(pageNum, pageSize);
        page(page, queryWrapper);
        return new P<>(page.getTotal(), page.getRecords());
    }

    @Override
    public int updateByIdAndExpected(RobotOrder order, Integer expected) {
        return baseMapper.updateExpected(order, expected);
    }

    @Override
    public RobotOrder getMaxBuyPriceOrder(Integer bourser, String symbol) {
        return baseMapper.getMaxBuyPriceOrder(bourser, symbol);
    }

    @Override
    public RobotOrder getMinSellPriceOrder(Integer bourser, String symbol) {
        return baseMapper.getMinSellPriceOrder(bourser, symbol);
    }

    @Override
    public void volumeOrder(Integer bourse, String symbol, int jobTimes) {
        // TODO api 修改
        /*BourseApi bourseApi = bourseApiService.getUserApi(Constant.SUPER_ADMIN_USERNAME, bourse);

        if (null == bourseApi) {
            throw new TransactionException("未配置交易所API");
        }
        RobotStrategy robotStrategy = robotStrategyService.getByBourseAndSymbol(bourse, symbol);
        if (null == robotStrategy) {
            throw new TransactionException("请先配置机器人挂单策略");
        }

        //获取实时买一卖一价量
        BoursePrice boursePrice = symbolSubService.getPrice(bourse, symbol);

        if (null == boursePrice) {
            throw new TransactionException("实时价格获取失败");
        }

        //挂单买卖价格
        BigDecimal buy = boursePrice.getBuyPrice();
        BigDecimal sell = boursePrice.getSellPrice();

        //获取最近买单与卖单
        Map<Object, Object> recentlyBuyOrder = getRecentlyOrder(bourse, symbol, true);
        Map<Object, Object> recentlySellOrder = getRecentlyOrder(bourse, symbol, false);

        //是否要挂买单
        boolean ableBuy = false;
        //是否要挂买单
        boolean ableSell = false;

        //本次是否需要吃单
        int times = getTimesOfTakeOrder(bourse, symbol);
        log.error("当前一分钟挂单定时任执行第{}次，需要吃单的次数为：{}", jobTimes, times);
        boolean shouldTakeOrder = jobTimes == times;

        if (shouldTakeOrder) {
            BigDecimal totalEatNum = volumeGet(bourse, symbol);
            if (robotStrategy.getDayVolume().compareTo(totalEatNum) <= 0) {
                log.error("交易所：{},交易对：{}, 日成交量：{}, 当前已成交：{}, 不再吃单", bourse, symbol, robotStrategy.getDayVolume(), totalEatNum);
            } else {
                //重新生成吃单次数
                setTimesOfTakeOrder(bourse, symbol);
                //随机吃买单或者卖单 吃买单机器人需挂买单
                boolean isEatBuy = isEatBuy();
                if (isEatBuy) {
                    //TODO 需要吃买单 挂一单卖单
                    log.error("吃买单");
                    eatOrder(bourse, symbol, bourseApi, robotStrategy, buy, sell, true);
                } else {
                    log.error("吃卖单");
                    //TODO 需要吃卖单 挂一单买单
                    eatOrder(bourse, symbol, bourseApi, robotStrategy, buy, sell, false);
                }
            }
        } else {
            //注意当offset很小的时候不下单
            BigDecimal currentOffset = sell.subtract(buy);
            if (BigDecimal.ZERO.compareTo(currentOffset) >= 0) {
                log.error("当前交易对:{},买价：{}, 卖价：{}，买价大于等于卖价不下单", symbol, buy, sell);
                return;
            }

            if (robotStrategy.getThreshold().compareTo(currentOffset) == 1) {
                log.error("当前交易对:{},买价：{}, 卖价：{}，差值：{}未达到阈值：{}不下单", symbol, buy, sell, currentOffset.toPlainString(), robotStrategy.getThreshold().toPlainString());
                return;
            }

            ableBuy = isNeedPlaceOrder(symbol, boursePrice.getBuyPrice(), boursePrice.getBuyNum(), recentlyBuyOrder, true);
            ableSell = isNeedPlaceOrder(symbol, boursePrice.getSellPrice(), boursePrice.getSellNum(), recentlySellOrder, false);

            final RobotOrderVo buyOrderVo = new RobotOrderVo();
            final RobotOrderVo sellOrderVo = new RobotOrderVo();

            if (ableBuy) {
                //不吃单 挂指定数量买单
                buyOrderVo.setBourse(bourse);
                buyOrderVo.setSymbol(symbol);
                buildOrder(buyOrderVo, robotStrategy, buy, sell, true);
            }

            if (ableSell) {
                //挂指定数量卖单
                sellOrderVo.setBourse(bourse);
                sellOrderVo.setSymbol(symbol);
                buildOrder(sellOrderVo, robotStrategy, buy, sell, false);
            }

            if (null != buyOrderVo.getOrderList() && buyOrderVo.getOrderList().size() > 0) {
                executorService.execute(() -> doOrder(bourseApi, true, buyOrderVo));
            }

            if (null != sellOrderVo.getOrderList() && sellOrderVo.getOrderList().size() > 0) {
                executorService.execute(() -> doOrder(bourseApi, false, sellOrderVo));
            }
        }*/
    }

    private void eatOrder (Integer bourse, String symbol, BourseApi api, RobotStrategy strategy, BigDecimal bid,
                           BigDecimal ask, boolean isEatBuy) {
        //TODO isEatBuy true 需要吃买单挂一单卖单否则需要吃卖单挂一单买单
        RobotOrder order = new RobotOrder();
        order.setBourse(bourse);
        order.setCreated(new Date());
        order.setStatus(0);
        order.setSymbol(symbol);
        order.setDealNum(BigDecimal.ZERO);

        order.setTradeType(isEatBuy ? TradeTypeEnum.SELL_LIMIT.getValue() : TradeTypeEnum.BUY_LIMIT.getValue());
        order.setId(sequence.nextId());

        order.setBid(bid);
        order.setAsk(ask);

        //挂单数量
        order.setNum(strategy.getMinNum());

        //挂买单 吃掉自己挂的最低价卖单 由于币夫会修改挂单价格这里吃当前卖一价
        //挂卖单 吃掉自己挂的最搞价买单 由于币夫会修改挂单价格这里吃当前买一价
//        BigDecimal eatPrice = new BigDecimal((String) recentlyOrder.get("price"));
        order.setPrice(isEatBuy ? bid : ask);
        order.setTotalPrice(order.getNum().multiply(order.getPrice()));

        executorService.execute(() -> doOrder(api, order));
    }

    private boolean isNeedPlaceOrder (String symbol, BigDecimal currentPrice, BigDecimal currentNum , Map<Object, Object> recentlyOrder,
                                      boolean isBuy) {
        boolean need = false;
        if (null == recentlyOrder || recentlyOrder.isEmpty()) {
            //最近未挂单
            log.error("最近未挂单");
            need = true;
        }
        else {
            int scale = getScale(symbol);
            BigDecimal price = new BigDecimal((String) recentlyOrder.get("price")).setScale(scale, BigDecimal.ROUND_HALF_UP);
            BigDecimal num = new BigDecimal((String) recentlyOrder.get("num"));
            log.info("当前买(卖)一价：{}, 买(卖)一量： {}, 最近机器人最大(小)买(卖)单价：{}, 买(卖)单量：{}",
                    currentPrice.setScale(scale, BigDecimal.ROUND_HALF_UP), currentNum, price, num);
            if ((currentPrice.compareTo(price) == 0) &&
                    (currentNum.compareTo(num) != 0)) {
                //价格相等量不一样撤单
                log.error("价格相等，数量不一样需要撤销订单");
                need = true;
            }
            if (isBuy) {
                if (currentPrice.setScale(scale, BigDecimal.ROUND_HALF_UP).compareTo(price) == 1) {
                    //当前买一价比你买价高需要撤单
                    log.error("当前买一价比机器人最高买价大需要撤单");
                    need = true;
                }
            } else {
                if (currentPrice.setScale(scale, BigDecimal.ROUND_HALF_UP).compareTo(price) == -1) {
                    //当前卖一价比你卖价低需要撤单
                    log.error("当前卖一价比机器人最低卖价小需要撤单");
                    need = true;
                }
            }
        }
        return need;
    }

    private void buildOrder (RobotOrderVo orderVo, RobotStrategy strategy,
                             BigDecimal bid, BigDecimal ask,  boolean isBuy) {
        List<RobotOrder> orderList = new ArrayList<>();
        //价格波动区间计算
        Symbol symbol = symbolService.getBuyName(orderVo.getSymbol());
        int scale = strategy.getThreshold().stripTrailingZeros().scale() + 1;
        BigDecimal min = getMinOffset(scale);
        BigDecimal max = min.multiply(new BigDecimal("5"));

        BigDecimal accumulated = BigDecimal.ZERO;
        for (int i = 0, v = strategy.getOrderNum(); i < v; i++) {
            accumulated = rangeRandom(min, max, scale).add(accumulated);
            RobotOrder order = new RobotOrder();
            order.setBourse(orderVo.getBourse());
            order.setCreated(new Date());
            order.setStatus(0);
            order.setSymbol(orderVo.getSymbol());
            order.setBaseCurrency(symbol.getBaseCurrency());
            order.setQuoteCurrency(symbol.getQuoteCurrency());
            order.setDealNum(BigDecimal.ZERO);

            order.setTradeType(isBuy ? TradeTypeEnum.BUY_LIMIT.getValue() : TradeTypeEnum.SELL_LIMIT.getValue());
            order.setId(sequence.nextId());

            order.setBid(bid);
            order.setAsk(ask);

            //挂单数量
            order.setNum(strategy.getMinNum());

            //挂单买卖价格设置
            order.setPrice(isBuy ? bid.add(accumulated) : ask.subtract(accumulated));
            order.setTotalPrice(order.getNum().multiply(order.getPrice()));

            orderList.add(order);
        }
        orderVo.setOrderList(orderList);
    }

    /**
     *
     * @param bourseApi
     * @param isBuy
     * @param orderVo
     */
    private void doOrder (BourseApi bourseApi, boolean isBuy,
                          RobotOrderVo orderVo) {
//        boolean success = false;
        switch (orderVo.getBourse()) {
            case 1:
                try {
                    HuobiUtil.order(bourseApi, orderVo.getOrderList());
//                    success = true;
                } catch (Exception e) {
                    log.error("火币机器人挂单失败：", e);
                }
                break;
            case 2:
                try {
                    BinanceUtil.order(bourseApi, orderVo.getOrderList());
//                    success = true;
                } catch (Exception e) {
                    log.error("币安机器人挂买单失败：", e);
                }
                break;
            case 3:
                try {
                    OkexUtil.order(bourseApi, orderVo.getOrderList());
//                    success = true;
                } catch (Exception e) {
                    log.error("Okex机器人挂买单失败：", e);
                }
                break;
            case 4:
                try {
                    BitforexUtil.order(bourseApi, orderVo.getOrderList());
//                    success = true;
                } catch (Exception e) {
                    log.error("币夫机器人挂买单失败：", e);
                }
                break;
            default:
                log.error("未知的交易所标识：" + orderVo.getBourse() );
                throw new TransactionException("交易所有误");
        }
        saveBatch(orderVo.getOrderList());
//        if (success) {
//        }
        executorService.execute(() -> cacheSuccessOrder(orderVo, isBuy));
    }

    private void doOrder (BourseApi bourseApi, RobotOrder robotOrder) {
        BitforexUtil.order(bourseApi, robotOrder);
        save(robotOrder);
    }

    /**
     * 获取最近挂单的买单最大价格或者卖单的最小价格的订单
     * @param bourse 交易所标识
     * @param symbol 交易对
     * @param isBuy 是否是买单
     */
    public Map<Object, Object> getRecentlyOrder (Integer bourse, String symbol, boolean isBuy) {
        String key = bourse + ":" + symbol + (isBuy ? HIGHEST_ORDER : LOWEST_ORDER);
        Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
        if (!map.isEmpty()) {
            RobotOrder order = getById((String) map.get("orderId"));
            //如果订单非提交与部分成交状态则需要找出最近一笔买价最大，卖价最低的订单
            //如果也没有则删除该缓存
            if (!BourseOrder.Status.PUBLISHED.value().equals(order.getStatus()) &&
                    !BourseOrder.Status.DEAL_PART.value().equals(order.getStatus())) {
                RobotOrder nextOrder = isBuy ? getMaxBuyPriceOrder(bourse, symbol) : getMinSellPriceOrder(bourse, symbol);
                if (null == nextOrder) {
                    redisTemplate.delete(key);
                    map = new HashMap<>();
                } else {
                    map.put("orderId", nextOrder.getId().toString());
                    map.put("price", nextOrder.getPrice().toPlainString());
                    map.put("num", nextOrder.getNum().toPlainString());
                    RobotOrderVo vo = new RobotOrderVo();
                    vo.setBourse(bourse);
                    vo.setSymbol(symbol);
                    vo.setCacheMap(map);
                    setRecentlyOrder(vo, isBuy);
                }
            }
        }
        return map;
    }

    /**
     * 缓存成功提交到交易所的订单信息
     * @param orderVo
     * @param isBuy
     */
    private void cacheSuccessOrder (RobotOrderVo orderVo, boolean isBuy) {
        List<RobotOrder> orderList = orderVo.getOrderList();
        //获取下单成功的订单中的最大或最小价格
        RobotOrder cacheOrder = orderList.parallelStream().filter(order -> order.getStatus().equals(BourseOrder.Status.PUBLISHED.value()))
//                .map(RobotOrder::getPrice)
                .reduce((a, b) -> a.getPrice().compareTo(b.getPrice()) > 0 ? (isBuy ? a : b) : (isBuy ? b : a)).orElse(null);
        if (null != cacheOrder) {
            log.info("下单成功，缓存订单信息");
            orderVo.getCacheMap().put("orderId", cacheOrder.getId().toString());
            orderVo.getCacheMap().put("price", cacheOrder.getPrice().toPlainString());
            orderVo.getCacheMap().put("num", cacheOrder.getNum().toPlainString());
            setRecentlyOrder(orderVo, isBuy);
        }
    }

    private void setRecentlyOrder (RobotOrderVo orderVo, boolean isBuy) {
        String key = orderVo.getBourse() + ":" + orderVo.getSymbol() + (isBuy ? HIGHEST_ORDER : LOWEST_ORDER);
        redisTemplate.opsForHash().putAll(key, orderVo.getCacheMap());
    }

    @Override
    public void clearRecentlyOrder (Integer bourse, String symbol, boolean isBuy) {
        String key = bourse + ":" + symbol + (isBuy ? HIGHEST_ORDER : LOWEST_ORDER);
        log.error("清楚订单信息缓存key：{}", key);
        redisTemplate.delete(key);
    }

    /**
     * 获取当前成交量
     * @param bourse
     * @param symbol
     * @return
     */
    private BigDecimal volumeGet (Integer bourse, String symbol) {
        BigDecimal volume = BigDecimal.ZERO;
        String key = bourse + ":" + symbol + "volume";
        String num = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(num)) {
            volume = new BigDecimal(num);
        }
        return volume;
    }

    @Override
    public void volumeSet (Integer bourse, String symbol, BigDecimal num) {
        if (BigDecimal.ZERO.compareTo(num) == -1) {
            String key = bourse + ":" + symbol + "volume";
            BigDecimal currentVolume = volumeGet(bourse, symbol);
//            redisTemplate.opsForValue().set(key, num.add(currentVolume).toPlainString(), 60, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(key, num.add(currentVolume).toPlainString());
        }
    }

    @Override
    public List<RobotOrder> getOrderByStatus(Integer ...status) {
        QueryWrapper<RobotOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("status", status);
        return list(queryWrapper);
    }

    @Override
    public boolean needCancel(Integer bourse, String symbol, boolean isBuy) {
        boolean need = false;
        int scale = getScale(symbol);
        BoursePrice boursePrice = symbolSubService.getPrice(bourse, symbol);
        if (null == boursePrice) {
            throw new TransactionException("实时价格获取失败");
        }
        BigDecimal price = isBuy ? boursePrice.getBuyPrice().setScale(scale, BigDecimal.ROUND_HALF_UP) : boursePrice.getSellPrice().setScale(scale, BigDecimal.ROUND_HALF_UP);
        BigDecimal num = isBuy ? boursePrice.getBuyNum() : boursePrice.getSellNum();

        Map<Object, Object> recentlyOrder = getRecentlyOrder(bourse, symbol, isBuy);
        if (!recentlyOrder.isEmpty()) {
            BigDecimal recentlyPrice = new BigDecimal((String) recentlyOrder.get("price")).setScale(scale, BigDecimal.ROUND_HALF_UP);
            BigDecimal recentlyNum = new BigDecimal((String) recentlyOrder.get("num"));
            log.info("当前买(卖)一价：{}, 买(卖)一量： {}, 最近机器人最大(小)买(卖)单价：{}, 买(卖)单量：{}",
                    price, num, recentlyPrice, recentlyNum);

            if ((price.compareTo(recentlyPrice) == 0) &&
                    (num.compareTo(recentlyNum) != 0)) {
                //价格相等量不一样撤单
                log.error("买(卖)单价格相等，数量不一样需要撤销订单");
                need = true;
            }

            if(isBuy) {
                if (price.compareTo(recentlyPrice) == 1) {
                    //当前买一价比你买家高需要撤单
                    log.error("当前买一价比机器人最高买价大需要撤单");
                    need = true;
                }
            } else {
                if (price.compareTo(recentlyPrice) == -1) {
                    //当前买一价比你买家高需要撤单
                    log.error("当前卖一价比机器人最低卖价小需要撤单");
                    need = true;
                }
            }
        }
        return need;
    }

    /**
     * 获取随机区间价格
     * @param min
     * @param max
     * @return
     */
    private BigDecimal rangeRandom (BigDecimal min, BigDecimal max, int scale) {
        return min.add(max.subtract(min).multiply(new BigDecimal(new Random().nextDouble()))).setScale(scale, BigDecimal.ROUND_DOWN);
    }

    /**
     * 获取 0.1 0.001等
     * @param scale 最大有效位数
     * @return
     */
    private BigDecimal getMinOffset (int scale) {
        StringBuilder sb = new StringBuilder();
        sb.append("0.");
        for (int i = 0; i < scale; i++) {
            if (i == scale - 1) {
                sb.append("1");
            } else {
                sb.append("0");
            }
        }
        return new BigDecimal(sb.toString());
    }

    /**
     * 缓存哪一次成交订单
     * 15秒一次 一分钟执行4次 在4次选一次成交
     * 第一次不能成交
     */
    private void setTimesOfTakeOrder (Integer bourse, String symbol) {
        String key = bourse + ":" + symbol + TIMES_TAKE_ORDER;
        int min = 2;
        int max = 4;
        long round = Math.round(min + (max - min) * new Random().nextDouble());
        redisTemplate.opsForValue().set(key, String.valueOf(round));
    }

    private int getTimesOfTakeOrder (Integer bourse, String symbol) {
        String key = bourse + ":" + symbol + TIMES_TAKE_ORDER;
        String s = redisTemplate.opsForValue().get(key);
        return Integer.parseInt(s);
    }

    /**
     * 随机返回吃买单还是卖单
     * @return
     */
    private boolean isEatBuy () {
        return (new Random().nextInt(1000) & 1) == 0;
    }

    private int getScale (String symbol) {
        if ("ctceth".equals(symbol)) {
            return 7;
        }
        if ("ctcusdt".equals(symbol)) {
            return 6;
        }
        return 5;
    }

    @Override
    public void afterPropertiesSet() {
        setTimesOfTakeOrder(4, "ctcusdt");
        setTimesOfTakeOrder(4, "ctceth");
    }

    @Override
    public ClassifyVolumeVo volumeStatistics() {
        ClassifyVolumeVo vo = new ClassifyVolumeVo();
        List<SymbolVolumeVo> voList = baseMapper.volumeStatistics();
        if (null != voList && voList.size() > 0) {
            Map<Integer, List<SymbolVolumeVo>> collect = voList.parallelStream().collect(Collectors.groupingBy(SymbolVolumeVo::getBourse));
            for (Map.Entry<Integer, List<SymbolVolumeVo>> entry : collect.entrySet()) {
                Map<String, Double> map = entry.getValue().parallelStream().collect(Collectors.toMap(SymbolVolumeVo::getSymbol, SymbolVolumeVo::getTotalDealNum));
                switch (entry.getKey()) {
                    case 1:
                        vo.setHuobi(map);
                        break;
                    case 2:
                        vo.setBinance(map);
                        break;
                    case 3:
                        vo.setOkex(map);
                        break;
                    case 4:
                        vo.setBitforex(map);
                        break;
                }
            }
        }
        return vo;
    }

    @Override
    public Map<String, Object> ctcOrderNumCount () {
        Map<String, Object> map = new HashMap<>();
        //all
        List<Map<String, Double>> allList = baseMapper.ctcOrderNumCount(null);
        //buy
        List<Map<String, Double>> buyList = baseMapper.ctcOrderNumCount(3);
        //sell
        List<Map<String, Double>> sellList = baseMapper.ctcOrderNumCount(4);

        map.put("totalNum", allList);
        map.put("buyNum", buyList);
        map.put("sellList", sellList);
        return map;
    }

    @Override
    public Map<String, Object> feeCount () {

        Map<String, Object> map = new HashMap<>();

        List<Map<String, Double>> ctcFeeList = baseMapper.feeCount("'ctc%'", 3);
        List<Map<String, Double>> usdtFeeList = baseMapper.feeCount("'%usdt'", 4);
        List<Map<String, Double>> ethFeeList = baseMapper.feeCount("'%eth'", 4);

        map.put("ctcFee", ctcFeeList);
        map.put("usdtFee", usdtFeeList);
        map.put("ethFee", ethFeeList);

        return map;
    }
}
